AB4D Forum
MouseWheelMessageFilter - Printable Version

+- AB4D Forum (https://forum.ab4d.com)
+-- Forum: Products Forums (https://forum.ab4d.com/forumdisplay.php?fid=4)
+--- Forum: Ab3d.PowerToys (https://forum.ab4d.com/forumdisplay.php?fid=9)
+--- Thread: MouseWheelMessageFilter (/showthread.php?tid=4240)



MouseWheelMessageFilter - GraPhiX - 02-18-2021

Hello
my first post, i am new to PowerToys purchased today, i am going through the samples and converting from C# to VB.NET, i have a project i have been working on for 3- 4 years and it is in VB.NET unfortunately i am not good with C#.

I have converted most of a sample i am interested in but having an issue with this class:


Code:
 public class MouseWheelMessageFilter : IMessageFilter
    {
        private const int WM_MOUSEWHEEL = 0x020A;
        private FrameworkElement _element;

        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

        public static void RegisterMouseWheelHandling(FrameworkElement element)
        {
            var mouseWheelMessageFilter = new MouseWheelMessageFilter(element);
        }

        private MouseWheelMessageFilter(FrameworkElement element)
        {
            _element = element;

            _element.Loaded += delegate(object sender, RoutedEventArgs args)
            {
                System.Windows.Forms.Application.AddMessageFilter(this);
            };

            _element.Unloaded += delegate(object sender, RoutedEventArgs args)
            {
                System.Windows.Forms.Application.RemoveMessageFilter(this);
            };
        }

        public bool PreFilterMessage(ref Message m)
        {
            if (!_element.IsVisible)
                return false;

            if (m.Msg == WM_MOUSEWHEEL)
            {
                Rect rect = new Rect(0, 0, _element.ActualWidth, _element.ActualHeight);
                System.Windows.Point pt = Mouse.GetPosition(_element);

                if (rect.Contains(pt))
                {
                    HwndSource hwndSource = (HwndSource)HwndSource.FromVisual(_element);
                    SendMessage(hwndSource.Handle, m.Msg, m.WParam, m.LParam);
                    return true;
                }
            }

            return false;
        }
    }


i have tried to convert it to VB but it does not work :( can anyone point me in the right direction this is what i have:


Code:
Public Class MouseWheelMessageFilter
        Inherits IMessageFilter


        Private Const WM_MOUSEWHEEL As Integer = &H20A
        Private _element As FrameworkElement
        <DllImport("user32.dll")>
        Public Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
        End Function

        Public Sub New(ByVal element As FrameworkElement)
            _element = element
        End Sub

        Public Function PreFilterMessage(ByRef m As Message) As Boolean
            If m.Msg = WM_MOUSEWHEEL Then
                Dim rect As Rect = New Rect(0, 0, _element.ActualWidth, _element.ActualHeight)
                Dim pt As Point = Mouse.GetPosition(_element)

                If rect.Contains(pt) Then
                    Dim hwndSource As HwndSource = CType(hwndSource.FromVisual(_element), HwndSource)
                    SendMessage(hwndSource.Handle, m.Msg, m.WParam, m.LParam)
                    Return True
                End If
            End If

            Return False
        End Function
    End Class



RE: MouseWheelMessageFilter - abenedik - 02-19-2021

I am not familiar with VB.Net but I see that you are missing the part that subscribes to calls AddMessageFilter and RemoveMessageFilter:

Code:
       public static void RegisterMouseWheelHandling(FrameworkElement element)
       {
           var mouseWheelMessageFilter = new MouseWheelMessageFilter(element);
       }

       private MouseWheelMessageFilter(FrameworkElement element)
       {
           _element = element;

           _element.Loaded += delegate(object sender, RoutedEventArgs args)
           {
               System.Windows.Forms.Application.AddMessageFilter(this);
           };

           _element.Unloaded += delegate(object sender, RoutedEventArgs args)
           {
               System.Windows.Forms.Application.RemoveMessageFilter(this);
           };
       }

The "private MouseWheelMessageFilter(FrameworkElement element)" line create a private constructor for the MouseWheelMessageFilter class. This means that the MouseWheelMessageFilter class can be created only from the public static method RegisterMouseWheelHandling.

You can also change that so that you have a standard constructor that takes the FrameworkElement as a parameter. 

The important thing (that is missing from your code) is that you need to subscribe element (as FrameworkElement) Loaded and Unloaded event. In the Loaded event you call System.Windows.Forms.Application.AddMessageFilter and pass an instance of MouseWheelMessageFilter object as a parameter. In the Unloaded event you call RemoveMessageFilter method.


RE: MouseWheelMessageFilter - GraPhiX - 02-19-2021

Hi thank you for your reply, i have got further along but it is still not quite right :( 


Code:
Public Class MouseWheelMessageFilter
        Implements IMessageFilter

        Private Sub New(ByVal element As FrameworkElement)
            Me._element = element
            AddHandler Me._element.Loaded, (sender, args) >= Application.AddMessageFilter(Me)
            AddHandler Me._element.Unloaded, (sender, args) >= Application.RemoveMessageFilter(Me)
        End Sub

        Public Function PreFilterMessage(ByRef m As Message) As Boolean
            Dim flag2 As Boolean
            If Me._element.IsVisible Then
                If (m.Msg = &H20A) Then
                    Dim rect As New Rect(0, 0, Me._element.ActualWidth, Me._element.ActualHeight)
                    If rect.Contains(Mouse.GetPosition(Me._element)) Then
                        MouseWheelMessageFilter.SendMessage(DirectCast(PresentationSource.FromVisual(Me._element), HwndSource).Handle, m.Msg, m.WParam, m.LParam)
                        Return True
                    End If
                End If
                flag2 = False
            Else
                flag2 = False
            End If
            Return flag2
        End Function

        Public Shared Sub RegisterMouseWheelHandling(ByVal element As FrameworkElement)
            Dim filter As New MouseWheelMessageFilter(element)
        End Sub

        <DllImport("user32.dll")>
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
        End Function


        ' Fields
        Private Const WM_MOUSEWHEEL As Integer = &H20A
        Private _element As FrameworkElement
    End Class



I will look at the URL you sent me see if i can work it out.
Regards
Kev


RE: MouseWheelMessageFilter - GraPhiX - 02-19-2021

I got it working :) not 100% sure its clean but it works i have commented out the addhandler the mouse capture works but not sure why the addhandler causes grief

here is the conversion from C# class to VB.NET if anyone else can make use :)


Code:
'Imports System
'Imports System.Collections.Generic
'Imports System.ComponentModel
'Imports System.Data
'Imports System.Drawing
'Imports System.Linq
Imports System.Runtime.InteropServices
'Imports System.Text
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Forms
Imports System.Windows.Input
Imports System.Windows.Interop
Imports System.Windows.Media.Media3D
Imports Ab3d.Cameras
Imports Ab3d.Common.Cameras
Imports Ab3d.Common.EventManager3D
Imports Ab3d.Controls
Imports Ab3d.Utilities
Imports HorizontalAlignment = System.Windows.HorizontalAlignment
Imports System.Windows.Forms.Integration
Imports System.Windows.Media
'Imports MouseEventArgs = System.Windows.Forms.MouseEventArgs
'Imports Point = System.Drawing.Point


Partial Public Class FRM_3DViewer
    Inherits Form

    Private _viewport3D As Viewport3D
    Private _targetPositionCamera As TargetPositionCamera
    Private _mouseCameraController As MouseCameraController
    Private _rootGrid As Grid
    Private _eventManager3D As EventManager3D

    Dim _isSelectedBoxClicked As Boolean

    Dim _totalClickedHeight As Double

    Private _normalMaterial As DiffuseMaterial = New DiffuseMaterial(System.Windows.Media.Brushes.Silver)
    Private _selectedMaterial As DiffuseMaterial = New DiffuseMaterial(System.Windows.Media.Brushes.Orange)
    Private _clickedMaterial As DiffuseMaterial = New DiffuseMaterial(System.Windows.Media.Brushes.Red)

    Public Sub New()

        InitializeComponent()
        SetUpWpf3D()
        Setup3DObjects()

        MouseWheelMessageFilter.RegisterMouseWheelHandling(_rootGrid)


    End Sub

    Private Sub Setup3DObjects()
        Me._eventManager3D = New EventManager3D(Me._viewport3D)
        Dim visuald1 As New Ab3d.Visuals.WireGridVisual3D
        visuald1.Size = New Size(1000, 1000)
        visuald1.HeightCellsCount = 10
        visuald1.WidthCellsCount = 10
        visuald1.LineThickness = 3
        Dim visuald As Ab3d.Visuals.WireGridVisual3D = visuald1
        Me._viewport3D.Children.Add(visuald)
        Dim num As Integer = -3
        Do While True
            If (num > 3) Then
                Me.ToggleCameraAnimation()
                Return
            End If
            Dim num2 As Integer = -3
            Do While True
                If (num2 > 3) Then
                    num += 1
                    Exit Do
                End If
                Dim y As Double = ((5 - Math.Sqrt(CDbl(((num2 * num2) + (num * num))))) * 60)
                Dim visuald3 As New Ab3d.Visuals.BoxVisual3D
                visuald3.CenterPosition = New Point3D(CDbl((num2 * 100)), (y / 2), CDbl((num * 100)))
                visuald3.Size = New Size3D(80, y, 80)
                visuald3.Material = Me._normalMaterial
                Dim visuald2 As Ab3d.Visuals.BoxVisual3D = visuald3
                Me._viewport3D.Children.Add(visuald2)
                Dim eventSource As New VisualEventSource3D(visuald2)
                AddHandler eventSource.MouseEnter, New Mouse3DEventHandler(AddressOf Me.BoxOnMouseEnter)
                AddHandler eventSource.MouseLeave, New Mouse3DEventHandler(AddressOf Me.BoxOnMouseLeave)
                AddHandler eventSource.MouseClick, New MouseButton3DEventHandler(AddressOf Me.BoxOnMouseClick)
                Me._eventManager3D.RegisterEventSource3D(eventSource)
                num2 += 1
            Loop
        Loop

        ToggleCameraAnimation()
    End Sub
    Private Sub BoxOnMouseEnter(ByVal sender As Object, ByVal mouse3DEventArgs As Mouse3DEventArgs)
        Dim boxVisual3D = TryCast(mouse3DEventArgs.HitObject, Ab3d.Visuals.BoxVisual3D)
        If boxVisual3D Is Nothing Then Return
        _isSelectedBoxClicked = ReferenceEquals(boxVisual3D.Material, _clickedMaterial)
        boxVisual3D.Material = _selectedMaterial
    End Sub
    Private Sub BoxOnMouseLeave(ByVal sender As Object, ByVal mouse3DEventArgs As Mouse3DEventArgs)
        Dim boxVisual3D = TryCast(mouse3DEventArgs.HitObject, Ab3d.Visuals.BoxVisual3D)
        If boxVisual3D Is Nothing Then Return

        If _isSelectedBoxClicked Then
            boxVisual3D.Material = _clickedMaterial
        Else
            boxVisual3D.Material = _normalMaterial
        End If
    End Sub

    Private Sub BoxOnMouseClick(ByVal sender As Object, ByVal mouseButton3DEventArgs As MouseButton3DEventArgs)
        Dim boxVisual3D = TryCast(mouseButton3DEventArgs.HitObject, Ab3d.Visuals.BoxVisual3D)
        If boxVisual3D Is Nothing Then Return

        If Not _isSelectedBoxClicked Then
            boxVisual3D.Material = _clickedMaterial
            _isSelectedBoxClicked = True
            _totalClickedHeight += boxVisual3D.Size.Y
        Else
            boxVisual3D.Material = _normalMaterial
            _isSelectedBoxClicked = False
            _totalClickedHeight -= boxVisual3D.Size.Y
        End If

    End Sub
    Private Sub SetUpWpf3D()

        _rootGrid = New Grid()
        _rootGrid.Background = System.Windows.Media.Brushes.White
        _viewport3D = New Viewport3D()
        _rootGrid.Children.Add(_viewport3D)

        _targetPositionCamera = New Ab3d.Cameras.TargetPositionCamera()
        With _targetPositionCamera
            .TargetPosition = New Point3D(0, 0, 0)
            .Distance = 1300
            .Heading = 30
            .Attitude = -20
            .ShowCameraLight = ShowCameraLightType.Always
            .TargetViewport3D = _viewport3D
        End With
        _rootGrid.Children.Add(_targetPositionCamera)

        _mouseCameraController = New Ab3d.Controls.MouseCameraController()
        With _mouseCameraController
            .RotateCameraConditions = MouseCameraController.MouseAndKeyboardConditions.RightMouseButtonPressed
            .MoveCameraConditions = MouseCameraController.MouseAndKeyboardConditions.RightMouseButtonPressed Or MouseCameraController.MouseAndKeyboardConditions.ControlKey
            .EventsSourceElement = _rootGrid
            .TargetCamera = _targetPositionCamera
        End With
        _rootGrid.Children.Add(_mouseCameraController)

        Dim cameraControlPanel = New Ab3d.Controls.CameraControlPanel()
        With cameraControlPanel
            .VerticalAlignment = VerticalAlignment.Bottom
            .HorizontalAlignment = HorizontalAlignment.Right
            .Margin = New Thickness(5, 5, 5, 5)
            .Width = 225
            .Height = 75
            .ShowMoveButtons = True
            .TargetCamera = _targetPositionCamera
        End With
        _rootGrid.Children.Add(cameraControlPanel)
        ElementHost1.Child = _rootGrid
    End Sub


    Private Sub BTN_animateButton_Click(sender As Object, e As EventArgs) Handles BTN_animateButton.Click
        ToggleCameraAnimation()

    End Sub
    Private Sub ToggleCameraAnimation()
        If _targetPositionCamera.IsRotating Then
            _targetPositionCamera.StopRotation()
            BTN_animateButton.Text = "Start animation"
        Else
            _targetPositionCamera.StartRotation(10, 0)
            BTN_animateButton.Text = "Stop animation"
        End If
    End Sub


    Public Class MouseWheelMessageFilter
        Implements IMessageFilter

        Private Const WM_MOUSEWHEEL As Integer = &H20A
        Private _element As FrameworkElement
        Private sender As Object
        Private args As Object

        Private Sub New(ByVal element As FrameworkElement)
            Me._element = element

            'AddHandler Me._element.Loaded, (sender, args) >= Application.AddMessageFilter(Me)
            'AddHandler Me._element.Unloaded, (sender, args) >= Application.RemoveMessageFilter(Me)
        End Sub



        Public Shared Sub RegisterMouseWheelHandling(ByVal element As FrameworkElement)
            Dim filter As New MouseWheelMessageFilter(element)
        End Sub

        <DllImport("user32.dll")>
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
        End Function

        Public Function IMessageFilter_PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
            Dim flag2 As Boolean
            If Me._element.IsVisible Then
                If (m.Msg = &H20A) Then
                    Dim rect As New Rect(0, 0, Me._element.ActualWidth, Me._element.ActualHeight)
                    If rect.Contains(Mouse.GetPosition(Me._element)) Then
                        MouseWheelMessageFilter.SendMessage(DirectCast(PresentationSource.FromVisual(Me._element), HwndSource).Handle, m.Msg, m.WParam, m.LParam)
                        Return True
                    End If
                End If
                flag2 = False
            Else
                flag2 = False
            End If
            Return flag2
        End Function
    End Class



End Class



RE: MouseWheelMessageFilter - abenedik - 02-19-2021

Great!

Thank you very much for sharing VB.Net code!


RE: MouseWheelMessageFilter - GraPhiX - 02-19-2021

(02-19-2021, 02:14 PM)abenedik Wrote: Great!

Thank you very much for sharing VB.Net code!

No problem, now all I have to do is work out how to import and export models with Assimp. 
What I need is a model viewer/convertor hence the purchase.
I wish there were VB examples converting and not quite understand C# makes the job twice as difficult


RE: MouseWheelMessageFilter - GraPhiX - 02-19-2021

Now i have elementhost setup i have tried converting Assimp sample (the one i actually need)

i have converted all the subs and classes but the ShowModel sub as one issue, 

ContentVisual.Content = model3D

i assume this assigns the loaded model on a WPF form how do i get it to use my elementhost ? this is the code i have:


Code:
Private Sub ShowModel(ByVal model3D As Model3D, ByVal updateCamera As Boolean)


        ContentVisual.Content = model3D

        If Not Object.ReferenceEquals(model3D, Nothing) Then
            Me.ContentWireframeVisual.BeginInit
            Me.ContentWireframeVisual.ShowPolygonLines = Me.ReadPolygonIndicesCheckBox.IsChecked.GetValueOrDefault
            Me.ContentWireframeVisual.OriginalModel = model3D
            Me.ContentWireframeVisual.EndInit
            If updateCamera Then
                Dim bounds As Rect3D = model3D.Bounds
                Dim pointd As New Point3D((bounds.X + (bounds.SizeX / 2)), (bounds.Y + (bounds.SizeY / 2)), (bounds.Z + (bounds.SizeZ / 2)))
                Dim num As Double = Math.Sqrt((((bounds.SizeX * bounds.SizeX) + (bounds.SizeY * bounds.SizeY)) + (bounds.SizeZ * bounds.SizeZ)))
                Me.Camera1.TargetPosition = pointd
                Me.Camera1.Distance = (num * 2)
            End If
            Me.Camera1.ShowCameraLight = If(Not ModelUtils.HasAnyLight(model3D, True), ShowCameraLightType.Always, ShowCameraLightType.Never)
            Me.ShowInfoButton.IsEnabled = True
        End If

    End Sub



RE: MouseWheelMessageFilter - abenedik - 02-22-2021

In the AssimpWpfImporterSample the ContentVisual is defined in XAML:

            <Viewport3D Name="MainViewport">
                <ModelVisual3D x:Name="ContentVisual" />
                <visuals:WireframeVisual3D x:Name="ContentWireframeVisual" ShowPolygonLines="True" WireframeType="Wireframe" UseModelColor="False"
                                           LineColor="Black" LineThickness="1" />                
            </Viewport3D>


I see that you already have a field ContentVisual, but because of the exception, you get it seems that you did not yet create an instance of it. As seen from the XAML, you will need to assign it to a new instance of ModelVisual3D object and then add that instance to Viewport3D objects with (MainViewport is the field that is an instance of Viewport3D):

Private _contentVisual As ModelVisual3D

...

Me._contentVisual = new ModelVisual3D()
Me._viewport3D.Children.Add(_contentVisual)


RE: MouseWheelMessageFilter - GraPhiX - 02-22-2021

(02-22-2021, 10:25 AM)abenedik Wrote: In the AssimpWpfImporterSample the ContentVisual is defined in XAML:

            <Viewport3D Name="MainViewport">
                <ModelVisual3D x:Name="ContentVisual" />
                <visuals:WireframeVisual3D x:Name="ContentWireframeVisual" ShowPolygonLines="True" WireframeType="Wireframe" UseModelColor="False"
                                           LineColor="Black" LineThickness="1" />                
            </Viewport3D>


I see that you already have a field ContentVisual, but because of the exception, you get it seems that you did not yet create an instance of it. As seen from the XAML, you will need to assign it to a new instance of ModelVisual3D object and then add that instance to Viewport3D objects with (MainViewport is the field that is an instance of Viewport3D):

Private _contentVisual As ModelVisual3D

...

Me._contentVisual = new ModelVisual3D()
Me._viewport3D.Children.Add(_contentVisual)

Doh! simple when you write it like that :) thank you....... plodding on Model now loads :) now i need to reset the view to load another model at the moment i am adding to the scene i would rather clear it an load fresh each time.

Thank you for you help