Quantcast
Viewing all articles
Browse latest Browse all 18858

WPF ViewPort3D doesn't transmit Mouse Events to inner User Control

I’ve got a wpf app displaying a card with rounded corners. The card has two sides – front and back – and it can be turned over from one side to another by mouse right button clicking. Each side also has a button with “X “ for closing the app.

 
Two custom commands are created for turning over and closing the card:

   
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace TestViewPort3DClick
{
    public class VocCommands
    {
        static VocCommands()
        {
            InputGestureCollection switch_inputs = new InputGestureCollection();
            switch_inputs.Add(new KeyGesture(Key.Down, ModifierKeys.Control, "Ctrl+arrow up"));
            switch_inputs.Add(new KeyGesture(Key.Up, ModifierKeys.Control, "Ctrl+arrow down"));
            switch_ = new RoutedUICommand("Switch", "Switch", typeof(VocCommands), switch_inputs);

            InputGestureCollection close_inputs = new InputGestureCollection();
            close_inputs.Add(new KeyGesture(Key.Escape, ModifierKeys.None, "Esc"));
            close = new RoutedUICommand("Close", "Close", typeof(VocCommands), close_inputs);

        }

        private static RoutedUICommand switch_;
        public static RoutedUICommand Switch
        {
            get { return switch_; }
        }

        private static RoutedUICommand close;
        public static RoutedUICommand Close
        {
            get { return close; }
        }

    }
}



The card itself is a user control with Path-figure and a StackPanel. The CloseButton is attached to the Custom Command “Close” (Command="local:VocCommands.Close"):

   
<UserControl x:Class="TestViewPort3DClick.Card"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TestViewPort3DClick"
             mc:Ignorable="d"  
             d:DesignHeight="300" d:DesignWidth="300"><Grid ><Path Stroke="DarkGray" StrokeThickness="1" SnapsToDevicePixels="True"><Path.Fill><LinearGradientBrush StartPoint="0.2,0" EndPoint="0.8,1" ><LinearGradientBrush.GradientStops><GradientStop Color="White"  Offset="0"></GradientStop><GradientStop Color="White"  Offset="0.45"></GradientStop><GradientStop Color="LightBlue" Offset="0.9"></GradientStop><GradientStop Color="Gray" Offset="1"></GradientStop></LinearGradientBrush.GradientStops></LinearGradientBrush></Path.Fill><Path.Data><PathGeometry><PathGeometry.Figures><PathFigure StartPoint="20,0" IsClosed="True"><LineSegment Point="140,0"></LineSegment><ArcSegment Point="160,20" Size="20,20" SweepDirection="Clockwise"></ArcSegment><LineSegment Point="160,40"></LineSegment><ArcSegment Point="140,60" Size="20,20" SweepDirection="Clockwise"></ArcSegment><LineSegment Point="20,60"></LineSegment><ArcSegment Point="0,40" Size="20,20" SweepDirection="Clockwise"></ArcSegment><LineSegment Point="0,20"></LineSegment><ArcSegment Point="20,0" Size="20,20" SweepDirection="Clockwise"></ArcSegment></PathFigure></PathGeometry.Figures></PathGeometry></Path.Data></Path><StackPanel Margin="5" Name="MainSP"><Button Command="local:VocCommands.Close" HorizontalAlignment="Right" Name="CloseButton"  FontSize="6" Margin="0,0,10,0" Padding="0,-2,0,-2" >X</Button><TextBlock Name="InnerTB" TextWrapping="Wrap"  FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Chocolate" Text="{Binding Path=InnerText}"/></StackPanel></Grid></UserControl>




Code-behind:

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TestViewPort3DClick
{
    public partial class Card : UserControl
    {
        public Card()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        public static readonly DependencyProperty InnerTextProperty = DependencyProperty.Register("InnerText", typeof(string), typeof(Card));
        public string InnerText
        {
            get
            {
                return this.GetValue(InnerTextProperty) as string;
            }
            set
            {
                this.SetValue(InnerTextProperty, value);
            }
        }

        public RoutedEventHandler RightMouseButtonDown
        {
            get { return StackPanel_Click; }
        }

        private void StackPanel_Click(object sender, RoutedEventArgs e)
        {
            VocCommands.Switch.Execute(null, this);
        }
    }
}



The card is embedded in another user control with ViewPort3D (two times - a Front and a Back Side). So it can be turned over by means of RotateTransform3D:

 
<UserControl x:Class="TestViewPort3DClick.ViewPortCard"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TestViewPort3DClick"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             MouseRightButtonDown="StackPanel_Click" 
             MouseLeftButtonDown="StackPanel_Drug"><UserControl.Resources><Storyboard x:Key="sbdCardRotation"><DoubleAnimation 
                   Storyboard.TargetName="CubeAngleRotation" 
                   Storyboard.TargetProperty="Angle" 
                   Duration="0:0:1" x:Name="CubeAnimation" From="0" To="180"/><DoubleAnimation 
                   Storyboard.TargetName="FrontSideAngleRotation" 
                   Storyboard.TargetProperty="Angle" 
                   Duration="0:0:1"  From="0" To="180"/><DoubleAnimation 
                   Storyboard.TargetName="BackSideAngleRotation" 
                   Storyboard.TargetProperty="Angle" 
                   Duration="0:0:1"  From="0" To="180"/></Storyboard></UserControl.Resources><Viewport3D Name="ViewPort" Grid.Column="1" Grid.Row="2"><Viewport3D.Camera><PerspectiveCamera          
          LookDirection="1,0,0"
          UpDirection="0,1,0"
          Position="-30,0,0"
          NearPlaneDistance="0"
          FarPlaneDistance="100"
          FieldOfView="40"></PerspectiveCamera></Viewport3D.Camera><ModelVisual3D><ModelVisual3D.Content><DirectionalLight
             Color="White"
             Direction="-2,-3,-1" /></ModelVisual3D.Content></ModelVisual3D><ModelVisual3D><ModelVisual3D.Content><DirectionalLight
             Color="White"
             Direction="2,1,1" /></ModelVisual3D.Content></ModelVisual3D><ModelVisual3D><ModelVisual3D.Content><GeometryModel3D><GeometryModel3D.Geometry><MeshGeometry3D Positions="0,-5,-10 0.1,-5,-10 0,5,-10 0.1,5,-10
                                           0,-5,10 0.1,-5,10 0,5,10 0.1,5,10"
                      TriangleIndices="0,2,1 1,2,3 
                                                 0,1,4 1,5,4 1,7,5 1,3,7 
                                                 4,5,6 7,6,5 2,6,3 3,6,7"
                       Normals="0,1,0 0,1,0 1,0,0 1,0,0
                                 0,1,0 0,1,0 1,0,0 1,0,0" /></GeometryModel3D.Geometry><GeometryModel3D.Material><DiffuseMaterial Brush="Transparent" /></GeometryModel3D.Material></GeometryModel3D></ModelVisual3D.Content><ModelVisual3D.Transform><RotateTransform3D><RotateTransform3D.Rotation><AxisAngleRotation3D x:Name="CubeAngleRotation" 
                                     Axis="0 0 1" /></RotateTransform3D.Rotation></RotateTransform3D></ModelVisual3D.Transform></ModelVisual3D><Viewport2DVisual3D><Viewport2DVisual3D.Geometry><MeshGeometry3D
                Positions="0,-5,-10 0,-5,10 0,5,-10 0,5,10"
               TriangleIndices="0,1,2 2,1,3"
               TextureCoordinates="0,1 1,1 0,0 1,0"
                               /></Viewport2DVisual3D.Geometry><Viewport2DVisual3D.Material><DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" /></Viewport2DVisual3D.Material><Viewport2DVisual3D.Visual><local:Card x:Name="FrontSideCtrl" InnerText="Front Side"/></Viewport2DVisual3D.Visual><Viewport2DVisual3D.Transform><RotateTransform3D><RotateTransform3D.Rotation><AxisAngleRotation3D x:Name="FrontSideAngleRotation" 
                                       Axis="0 0 1" /></RotateTransform3D.Rotation></RotateTransform3D></Viewport2DVisual3D.Transform></Viewport2DVisual3D><Viewport2DVisual3D><Viewport2DVisual3D.Geometry><MeshGeometry3D
                Positions="0.1,-5,-10 0.1,-5,10 0.1,5,-10 0.1,5,10"
               TriangleIndices="0,2,1 1,2,3"
               TextureCoordinates=" 0,0 1,0 0,1 1,1"
                               /></Viewport2DVisual3D.Geometry><Viewport2DVisual3D.Material><DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" /></Viewport2DVisual3D.Material><Viewport2DVisual3D.Visual><local:Card x:Name="BackSideCtrl" InnerText="Back Side"/></Viewport2DVisual3D.Visual><Viewport2DVisual3D.Transform><RotateTransform3D><RotateTransform3D.Rotation><AxisAngleRotation3D x:Name="BackSideAngleRotation" 
                                       Axis="0 0 1" /></RotateTransform3D.Rotation></RotateTransform3D></Viewport2DVisual3D.Transform></Viewport2DVisual3D></Viewport3D></UserControl>


 
Code-behind:
 
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Media.Animation;

namespace TestViewPort3DClick
{
    public partial class ViewPortCard : UserControl
    {
        public ViewPortCard()
        {
            Side = CardSide.Front;
            InitializeComponent();
        }

        public Window ParentWindow
        { get { return Window.GetWindow(this); } }

        private double from;
        public double From { get { return from; } set { from = value; } }
        private double to;
        public double To { get { return to; } set { to = value;  } }

        public enum CardSide { Front, Back };

        private CardSide side;
        public CardSide Side
        {
            get { return side; }
            set
            {
                side = value;
                if
                (value == CardSide.Back)
                {
                    From = 180;
                    To = 0;
                }
                else if (value == CardSide.Front)
                {
                    From = 0;
                    To = 180;
                }
            }
        }

        private void StackPanel_Click(object sender, RoutedEventArgs e)
        {
            VocCommands.Switch.Execute(null, this);
        }

        private void CloseCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ParentWindow.Close();
        }

        public ExecutedRoutedEventHandler CloseCommand
        {
            get { return CloseCommand_Executed; }
        }

        public ExecutedRoutedEventHandler SwitchCommand
        {
            get { return SwitchCommand_Executed; }
        }

        private void SwitchCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Storyboard sbdCardRotation = (Storyboard)this.FindResource("sbdCardRotation");
            (sbdCardRotation.Children[0] as DoubleAnimation).To = To;
            (sbdCardRotation.Children[1] as DoubleAnimation).To = To;
            (sbdCardRotation.Children[2] as DoubleAnimation).To = To;
            (sbdCardRotation.Children[0] as DoubleAnimation).From = From;
            (sbdCardRotation.Children[1] as DoubleAnimation).From = From;
            (sbdCardRotation.Children[2] as DoubleAnimation).From = From;
            sbdCardRotation.Begin(this);

            if (Side == CardSide.Front)
                Side = CardSide.Back;
            else if (Side == CardSide.Back)
                Side = CardSide.Front;
        }

        private void StackPanel_Drug(object sender, RoutedEventArgs e)
        {
            ParentWindow.DragMove();
        }
    }
}


So the ViewPortCard User Control is used in the MainWindow:

 
<Window x:Class="TestViewPort3DClick.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestViewPort3DClick"
        Title="MainWindow"
        WindowStyle="None"
	AllowsTransparency="True"
	Background="Transparent"
        Height="100" Width="200"><local:ViewPortCard x:Name="VPCard"></local:ViewPortCard></Window>



Code-behind:

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TestViewPort3DClick
{
    public partial class MainWindow : Window
    {
        public bool IsBindingsSet { get; set; }

        public MainWindow()
        {
            InitializeComponent();

            if (!IsBindingsSet)
            {
                CommandBinding switch_binding = new CommandBinding(VocCommands.Switch);
                CommandBinding close_binding = new CommandBinding(VocCommands.Close);
                MainWindow w = this;
                switch_binding.Executed += w.SwitchCommand;
                close_binding.Executed += w.CloseCommand;
                w.CommandBindings.Add(switch_binding);
                w.CommandBindings.Add(close_binding);
                IsBindingsSet = true;
            }
        }

        public ExecutedRoutedEventHandler SwitchCommand
        {
            get { return VPCard.SwitchCommand; }
        }

        public ExecutedRoutedEventHandler CloseCommand
        {
            get { return VPCard.CloseCommand; }
        }
    }
}



The problem is that the Command “Close” doesn’t work on the Back Side. The ViewPort3D doesn't transmit mouse events to its inner embedded controls, does it? Why is that? And why does it do on the Front Side?

It is important, that the Command does work well when pressing Key Esc. So it is the problem with mouse events propagating, not command itself. I've tried hit testing for the CloseButton. The test has shown that the mouse hits the button. But the button doesn't receive the mouse event.


Viewing all articles
Browse latest Browse all 18858

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>