VB のたまご

作成日: 2017/03/07, 更新日: 2017/03/07



ルーティングイベント3

  •  ここでは、ルーティングイベントを自作してみます。主に使う場面は自作コントロールを作成する時になります。 それではまずは作ってみましょう。 ボタンを継承した自作ボタンクラスと、自作ボタンを作る画面クラスとコードビハインドの3つに分かれます。

  • スポンサーリンク


  •  まずは、空のクラスに以下を記述します。

  • ' ボタンを継承した自作ボタンを通して、自作ルーティングイベントの作成方法を学ぼう
    
    Public Class MyButton
        Inherits Button
    
        ' ルーティングイベントの作成と登録
        ' 第一引数・・・ルーティングイベントの名前(xxxEvent)とイベント名の後ろに「Event」を追加する
        ' 第二引数・・・ルーティングイベントのルーティング種類
        ' 第三引数・・・ルーティングイベントの型
        ' 第四引数・・・ルーティングイベントを管理しているクラスの型(=イベントの発生元クラス)
        Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
            "Tap",
            RoutingStrategy.Bubble,
            GetType(RoutedEventHandler),
            GetType(MyButton))
    
        ' プロパティ形式で作成する、CLR用ラッパーイベントの作成
        Public Custom Event Tap As RoutedEventHandler
    
            AddHandler(value As RoutedEventHandler)
                Me.AddHandler(TapEvent, value)
            End AddHandler
    
            RemoveHandler(value As RoutedEventHandler)
                Me.RemoveHandler(TapEvent, value)
            End RemoveHandler
    
            RaiseEvent(sender As Object, e As RoutedEventArgs)
                Me.RaiseEvent(e)
            End RaiseEvent
    
        End Event
    
        Private Sub RaiseTapEvent()
    
            MyBase.RaiseEvent(New RoutedEventArgs(TapEvent))
    
        End Sub
    
        Protected Overrides Sub OnClick()
    
            Me.RaiseTapEvent()
    
        End Sub
    
    End Class
    

  •  自作ボタンを作成したら一回ビルドします。Visual Studio が認識してくれるようになります。 ルーティングイベントは、ルーティングイベント作成、CLRラッパーイベント作成、任意でイベント発生するきっかけ(OnXxx など)を実装します。 静的メンバーで読み取り専用な扱いが特徴的です。CLR イベントをプロパティ形式で作っていくのも初めてかと思います。

  •  それでは、この自作ボタンを Xaml 上で使ってみましょう。またはデフォルトの「MainWindow」に記述しても構いません。 自作ボタンの「MyButton」を使うためには、頭に local: を付ける必要があります。 今のところは、名前空間.MyButton とフルネームで名指しして使うのがお作法だと思ってください。

  • <Window x:Class="RoutedEventWindow1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:w06_WpfSystem2"
            mc:Ignorable="d"
            Title="RoutedEventWindow1" Height="300" Width="300">
    
        <Grid>
    
            <local:MyButton Content="mybutton1" Width="120" Height="30"
                            Tap="MyButton_Tap" />
    
        </Grid>
        
    </Window>
    

    Public Class RoutedEventWindow1
    
        Private Sub MyButton_Tap(sender As Object, e As RoutedEventArgs)
    
            MessageBox.Show("OnClick で発生する、なんちゃって Tap イベントです")
    
        End Sub
    
    End Class
    

  •  実行してみて、ボタンのクリックでメッセージが表示されれば OK です。

  • スポンサーリンク


  •  今度はトンネリングイベントのサンプルです。

  • Public Class MyButton2
        Inherits Button
    
        Public Shared ReadOnly PreviewTapEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
            "PreviewTap",
            RoutingStrategy.Tunnel,
            GetType(RoutedEventHandler),
            GetType(MyButton2))
    
        Public Custom Event PreviewTap As RoutedEventHandler
    
            AddHandler(value As RoutedEventHandler)
                Me.AddHandler(PreviewTapEvent, value)
            End AddHandler
    
            RemoveHandler(value As RoutedEventHandler)
                Me.RemoveHandler(PreviewTapEvent, value)
            End RemoveHandler
    
            RaiseEvent(sender As Object, e As RoutedEventArgs)
                Me.RaiseEvent(e)
            End RaiseEvent
    
        End Event
    
        Private Sub RaisePreviewTapEvent()
    
            Me.RaiseEvent(New RoutedEventArgs(PreviewTapEvent))
    
        End Sub
    
        Protected Overrides Sub OnMouseLeftButtonUp(e As MouseButtonEventArgs)
    
            MyBase.OnMouseLeftButtonUp(e)
            Me.RaisePreviewTapEvent()
    
        End Sub
    
    End Class
    

  •  自作ボタンを作成したら一回ビルドします。Visual Studio が認識してくれるようになります。

  • <Window x:Class="RoutedEventWindow2"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:w06_WpfSystem2"
            mc:Ignorable="d"
            Title="RoutedEventWindow2" Height="300" Width="300">
       
        <Grid>
    
            <local:MyButton2 Content="mybutton21" Width="120" Height="30" 
                             PreviewTap="MyButton2_PreviewTap" />
    
        </Grid>
        
    </Window>
    

    Public Class RoutedEventWindow2
    
        Private Sub MyButton2_PreviewTap(sender As Object, e As RoutedEventArgs)
    
            MessageBox.Show("OnMouseLeftButtonUp で発生する、なんちゃって PreviewTap イベントです")
    
        End Sub
    
    End Class
    

  •  先程記載したサンプルと同じように、ボタンクリックでメッセージが表示されたら OK です。

  •  それでは、トンネリングイベントとバブルイベントのルーティングを見てみましょう。

  • <Window x:Class="RoutedEventWindow3"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:w06_WpfSystem2"
            mc:Ignorable="d"
            Title="RoutedEventWindow3" Height="300" Width="300">
    
        <Grid
            Name="grid1"
            local:MyButton.Tap="MyButton_Tap"
            local:MyButton2.PreviewTap="MyButton2_PreviewTap">
    
            <StackPanel 
                Name="stackpanel1"
                Margin="10"
                local:MyButton.Tap="MyButton_Tap"
                local:MyButton2.PreviewTap="MyButton2_PreviewTap">
    
                <local:MyButton
                    x:Name="mybutton1"
                    Content="mybutton1" 
                    Tap="MyButton_Tap" />
         
                <local:MyButton2 
                    x:Name="mybutton2_1"
                    Content="mybutton2_1" 
                    PreviewTap="MyButton2_PreviewTap" />
    
            </StackPanel>
            
        </Grid>
        
    </Window>
    

    Public Class RoutedEventWindow3
    
        Private Sub MyButton_Tap(sender As Object, e As RoutedEventArgs)
    
            Dim ctrl = TryCast(sender, FrameworkElement)
            If ctrl Is Nothing Then
                Exit Sub
            End If
    
            Console.WriteLine($"MyButton_Tap / {ctrl.Name}({ctrl.GetType()})")
    
        End Sub
    
        Private Sub MyButton2_PreviewTap(sender As Object, e As RoutedEventArgs)
    
            Dim ctrl = TryCast(sender, FrameworkElement)
            If ctrl Is Nothing Then
                Exit Sub
            End If
    
            Console.WriteLine($"MyButton2_PreviewTap / {ctrl.Name}({ctrl.GetType()})")
    
        End Sub
    
    End Class
    

  •  mybutton1 ボタンをクリック、mybutton21 ボタンをクリックした結果が以下です。 ちゃんとルーティング通りにイベントが発生していますね。

  • 出力結果
    MyButton_Tap / mybutton1(w06_WpfSystem2.MyButton)
    MyButton_Tap / stackpanel1(System.Windows.Controls.StackPanel)
    MyButton_Tap / grid1(System.Windows.Controls.Grid)
    MyButton2_PreviewTap / grid1(System.Windows.Controls.Grid)
    MyButton2_PreviewTap / stackpanel1(System.Windows.Controls.StackPanel)
    MyButton2_PreviewTap / mybutton2_1(w06_WpfSystem2.MyButton2)