none
ViewPort3D

    Question

  • I am using ViewPort3D in a user control.  the viewport3d's child has an image and a button control. The image control has to display a tooltip and a mouseover event(sets a style on mouseover). But the events are not firing. Is that the way it is supposed to be or is there any way to get the events of the child controls in the viewport3D to fire?


    Gopra V

    Friday, August 31, 2012 10:45 AM

Answers

  • Hi,

    Thanks for the replies.

    I am aware of the VisualTreeHelper.HitTest method.  But what i am looking for is a way to get the child control's events to fire automatically without relying on VisualTreeHelper.HitTest method.

    The reason is, i am trying to set the child of the viewport3D dynamically and hence i want the original event handlers of the child to fire.


    Gopra V

    Hello Gopra.

    I did a 3D control some time ago that the items contained within the ViewPort3D Control had several events associated with them and I had no difficulty getting them to fire. 

    While I'm not the sharpest tool in the shed and I probably did not understand fully what you are trying to do... here is a sample based on what I think you said...

    The Xaml for the control...

    <UserControl
    	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"
    	mc:Ignorable="d"
    	x:Class="ViewPort3dTesting.viewport3DControl"
    	x:Name="UserControl"
    	d:DesignWidth="300" d:DesignHeight="300">
    	
    	<UserControl.Resources>
    		<Style x:Key="ImageStyle" TargetType="{x:Type Image}">
    			<Setter Property="Opacity" Value=".5"/>
    		</Style>
    		<Style x:Key="ImageStyle2" TargetType="{x:Type Image}">
    			<Setter Property="Opacity" Value="1"/>
    		</Style>
    		<Storyboard x:Key="Storyboard1">
    			<Rotation3DAnimationUsingKeyFrames Storyboard.TargetProperty="(Visual3D.Transform).(Transform3DGroup.Children)[2].(RotateTransform3D.Rotation)" Storyboard.TargetName="viewport2DVisual3D">
    				<EasingRotation3DKeyFrame KeyTime="0">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,1,0" Angle="10"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    				<EasingRotation3DKeyFrame KeyTime="0:0:0.4">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,-1,0" Angle="10"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    				<EasingRotation3DKeyFrame KeyTime="0:0:0.5">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,1,0" Angle="0"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    			</Rotation3DAnimationUsingKeyFrames>
    		</Storyboard>
    		<Storyboard x:Key="Storyboard2">
    			<Rotation3DAnimationUsingKeyFrames Storyboard.TargetProperty="(Visual3D.Transform).(Transform3DGroup.Children)[2].(RotateTransform3D.Rotation)" Storyboard.TargetName="viewport2DVisual3D">
    				<EasingRotation3DKeyFrame KeyTime="0">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,1,0" Angle="0"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    				<EasingRotation3DKeyFrame KeyTime="0:0:0.1">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,-1,0" Angle="10"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    				<EasingRotation3DKeyFrame KeyTime="0:0:0.5">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,1,0" Angle="10"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    			</Rotation3DAnimationUsingKeyFrames>
    		</Storyboard>
    	</UserControl.Resources>
    	<Grid x:Name="LayoutRoot">
    		<Viewport3D x:Name="viewport3D" HorizontalAlignment="Center" Height="300" VerticalAlignment="Center" Width="300" MouseEnter="viewport3D_MouseEnter" MouseLeave="viewport3D_MouseLeave">
    			<Viewport3D.Camera>
    				<PerspectiveCamera FieldOfView="40" FarPlaneDistance="300" LookDirection="0,0,-1" NearPlaneDistance="0" Position="0,0,3" UpDirection="0,1,0"/>
    			</Viewport3D.Camera>
    			<Viewport2DVisual3D x:Name="viewport2DVisual3D">
    				<Viewport2DVisual3D.Geometry>
    					<MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0" 
    						TextureCoordinates="0,0 0,1 1,1 1,0"
    						TriangleIndices="0 1 2 0 2 3"/>
    				</Viewport2DVisual3D.Geometry>
    				<Viewport2DVisual3D.Material>
    					<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="Transparent"/>
    				</Viewport2DVisual3D.Material>
    				<Viewport2DVisual3D.Transform>
    					<Transform3DGroup>
    						<TranslateTransform3D OffsetZ="0" OffsetX="0" OffsetY="0"/>
    						<ScaleTransform3D ScaleZ="1" ScaleY="1" ScaleX="1"/>
    						<RotateTransform3D d:EulerAngles="0,10,0">
    							<RotateTransform3D.Rotation>
    								<AxisAngleRotation3D Axis="0,1,0" Angle="10"/>
    							</RotateTransform3D.Rotation>
    						</RotateTransform3D>
    						<TranslateTransform3D OffsetZ="0" OffsetX="0" OffsetY="0"/>
    						<TranslateTransform3D OffsetZ="0" OffsetX="0" OffsetY="0"/>
    					</Transform3DGroup>
    				</Viewport2DVisual3D.Transform>
    				<Grid x:Name="myGrid" Width="100" Height="100" RenderTransformOrigin="0.5, 0.5">
    					<Grid.RowDefinitions>
    						<RowDefinition Height="70"/>
    						<RowDefinition Height="*"/>
    					</Grid.RowDefinitions>
    				</Grid>
    			</Viewport2DVisual3D>
    			<ModelVisual3D>
    				<ModelVisual3D.Content>
    					<DirectionalLight Color="White" Direction="0,0,-1"/>
    				</ModelVisual3D.Content>
    			</ModelVisual3D>
    		</Viewport3D>
    	</Grid>
    </UserControl>

    I added mouse events on the actual ViewPort3d Control and the Image control just to make sure both would do their thing and they seem to...

    The code-behind for that control...

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;
    using System.Windows.Media.Animation;
    namespace ViewPort3dTesting
    {
    	public partial class viewport3DControl : UserControl
    	{
    		public viewport3DControl()
    		{
    			this.InitializeComponent();
    		}
    		
    		public void AddItems()
    		{
    			myGrid.Children.Clear();
    			
    			Image img = new Image();
    			img.Source = new BitmapImage(new Uri("img1.png", UriKind.RelativeOrAbsolute));
    			img.HorizontalAlignment = HorizontalAlignment.Stretch;
    			img.VerticalAlignment = VerticalAlignment.Stretch;
    			img.Style = this.TryFindResource("ImageStyle") as Style;
    			img.ToolTip = img.Source.ToString();
    			img.MouseEnter += changeStyle;
    			myGrid.Children.Add(img);
    			Grid.SetRow(img, 0);
    			
    			Button btn = new Button();
    			btn.Content = "Click Me";
    			btn.HorizontalAlignment = HorizontalAlignment.Stretch;
    			btn.VerticalAlignment = VerticalAlignment.Stretch;
    			btn.Margin = new Thickness(5);
    			btn.Click += btnClicked;
    			myGrid.Children.Add(btn);
    			Grid.SetRow(btn, 1);
    		}
    		
    		private void btnClicked(object sender, System.Windows.RoutedEventArgs e)
    		{
    			MessageBox.Show("Clicked");
    		}
    		
    		private void changeStyle(object sender, MouseEventArgs e)
    		{
    			Image img = sender as Image;
    			img.Style = this.TryFindResource("ImageStyle2") as Style; 
    		}
    		private void viewport3D_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
    		{
    			Storyboard sb = this.TryFindResource("Storyboard1") as Storyboard;
    			sb.Begin();
    		}
    		private void viewport3D_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
    		{
    			Storyboard sb = this.TryFindResource("Storyboard2") as Storyboard;
    			sb.Begin();
    		}
    	}
    }

    And the MainWindow housing the control and which contains the button to add items dynamically to the control...

    <Window
    	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:local="clr-namespace:ViewPort3dTesting"
    	x:Class="ViewPort3dTesting.MainWindow"
    	x:Name="Window"
    	Title="MainWindow"
    	Width="640" Height="480">
    	<Grid x:Name="LayoutRoot">
    		<local:viewport3DControl x:Name="myControl" Margin="162,70.5"/>
    		<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    	</Grid>
    </Window>

    And the code-behind...

    using System.Windows;
    namespace ViewPort3dTesting
    {
    	public partial class MainWindow : Window
    	{
    		public MainWindow()
    		{
    			this.InitializeComponent();
    		}
    		private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
    		{
    			myControl.AddItems();
    		}
    	}
    }

    I stuck the sample project on my SkyDrive … http://sdrv.ms/RlBf9x   If you'd like to play with it.

    I really do hope you get it worked out quickly.

    ~Christine


    My Gallery


    Wednesday, September 05, 2012 4:58 PM

All replies

  • Hi Gopra,

    try using VisualTreeHelper.Hittest method to capture mouse events.

    http://msdn.microsoft.com/en-us/library/ms745195(v=vs.100).aspx

    Although, i am not too sure how it will work for changing styles on mouseover

    • Marked as answer by Gopra Friday, August 31, 2012 12:36 PM
    • Unmarked as answer by Gopra Friday, August 31, 2012 12:36 PM
    Friday, August 31, 2012 12:25 PM
  • Hi Gopra,

    What BalaG's solution is right, you could use VisualTreeHelper.HitTest method (Visual3D, HitTestFilterCallback, HitTestResultCallback, HitTestParameters3D)  to do the hittest on the 3D models. And check the return value.

    If you have any additional questions, please feel free to let me know.

    Have a nice day.


    Annabella Luo[MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, September 04, 2012 10:07 AM
    Moderator
  • Hi,

    Thanks for the replies.

    I am aware of the VisualTreeHelper.HitTest method.  But what i am looking for is a way to get the child control's events to fire automatically without relying on VisualTreeHelper.HitTest method.

    The reason is, i am trying to set the child of the viewport3D dynamically and hence i want the original event handlers of the child to fire.


    Gopra V

    Tuesday, September 04, 2012 10:46 AM
  • Hi Gopra,

    As far as my knowledge goes, i think it is not possible. Because the viewport3D container masks the events of its children. Viewport3D is mostly used only for display purposes.

    I dont think(again, w.r.t my knowledge) there is a way to get a ViewPort3D's dynamic child control's binded events to fire as it normally does in other containers such as a usercontrol or a stackpanel.

    Wednesday, September 05, 2012 12:48 PM
  • Hi,

    Thanks for the replies.

    I am aware of the VisualTreeHelper.HitTest method.  But what i am looking for is a way to get the child control's events to fire automatically without relying on VisualTreeHelper.HitTest method.

    The reason is, i am trying to set the child of the viewport3D dynamically and hence i want the original event handlers of the child to fire.


    Gopra V

    Hello Gopra.

    I did a 3D control some time ago that the items contained within the ViewPort3D Control had several events associated with them and I had no difficulty getting them to fire. 

    While I'm not the sharpest tool in the shed and I probably did not understand fully what you are trying to do... here is a sample based on what I think you said...

    The Xaml for the control...

    <UserControl
    	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"
    	mc:Ignorable="d"
    	x:Class="ViewPort3dTesting.viewport3DControl"
    	x:Name="UserControl"
    	d:DesignWidth="300" d:DesignHeight="300">
    	
    	<UserControl.Resources>
    		<Style x:Key="ImageStyle" TargetType="{x:Type Image}">
    			<Setter Property="Opacity" Value=".5"/>
    		</Style>
    		<Style x:Key="ImageStyle2" TargetType="{x:Type Image}">
    			<Setter Property="Opacity" Value="1"/>
    		</Style>
    		<Storyboard x:Key="Storyboard1">
    			<Rotation3DAnimationUsingKeyFrames Storyboard.TargetProperty="(Visual3D.Transform).(Transform3DGroup.Children)[2].(RotateTransform3D.Rotation)" Storyboard.TargetName="viewport2DVisual3D">
    				<EasingRotation3DKeyFrame KeyTime="0">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,1,0" Angle="10"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    				<EasingRotation3DKeyFrame KeyTime="0:0:0.4">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,-1,0" Angle="10"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    				<EasingRotation3DKeyFrame KeyTime="0:0:0.5">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,1,0" Angle="0"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    			</Rotation3DAnimationUsingKeyFrames>
    		</Storyboard>
    		<Storyboard x:Key="Storyboard2">
    			<Rotation3DAnimationUsingKeyFrames Storyboard.TargetProperty="(Visual3D.Transform).(Transform3DGroup.Children)[2].(RotateTransform3D.Rotation)" Storyboard.TargetName="viewport2DVisual3D">
    				<EasingRotation3DKeyFrame KeyTime="0">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,1,0" Angle="0"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    				<EasingRotation3DKeyFrame KeyTime="0:0:0.1">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,-1,0" Angle="10"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    				<EasingRotation3DKeyFrame KeyTime="0:0:0.5">
    					<EasingRotation3DKeyFrame.Value>
    						<AxisAngleRotation3D Axis="0,1,0" Angle="10"/>
    					</EasingRotation3DKeyFrame.Value>
    				</EasingRotation3DKeyFrame>
    			</Rotation3DAnimationUsingKeyFrames>
    		</Storyboard>
    	</UserControl.Resources>
    	<Grid x:Name="LayoutRoot">
    		<Viewport3D x:Name="viewport3D" HorizontalAlignment="Center" Height="300" VerticalAlignment="Center" Width="300" MouseEnter="viewport3D_MouseEnter" MouseLeave="viewport3D_MouseLeave">
    			<Viewport3D.Camera>
    				<PerspectiveCamera FieldOfView="40" FarPlaneDistance="300" LookDirection="0,0,-1" NearPlaneDistance="0" Position="0,0,3" UpDirection="0,1,0"/>
    			</Viewport3D.Camera>
    			<Viewport2DVisual3D x:Name="viewport2DVisual3D">
    				<Viewport2DVisual3D.Geometry>
    					<MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0" 
    						TextureCoordinates="0,0 0,1 1,1 1,0"
    						TriangleIndices="0 1 2 0 2 3"/>
    				</Viewport2DVisual3D.Geometry>
    				<Viewport2DVisual3D.Material>
    					<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="Transparent"/>
    				</Viewport2DVisual3D.Material>
    				<Viewport2DVisual3D.Transform>
    					<Transform3DGroup>
    						<TranslateTransform3D OffsetZ="0" OffsetX="0" OffsetY="0"/>
    						<ScaleTransform3D ScaleZ="1" ScaleY="1" ScaleX="1"/>
    						<RotateTransform3D d:EulerAngles="0,10,0">
    							<RotateTransform3D.Rotation>
    								<AxisAngleRotation3D Axis="0,1,0" Angle="10"/>
    							</RotateTransform3D.Rotation>
    						</RotateTransform3D>
    						<TranslateTransform3D OffsetZ="0" OffsetX="0" OffsetY="0"/>
    						<TranslateTransform3D OffsetZ="0" OffsetX="0" OffsetY="0"/>
    					</Transform3DGroup>
    				</Viewport2DVisual3D.Transform>
    				<Grid x:Name="myGrid" Width="100" Height="100" RenderTransformOrigin="0.5, 0.5">
    					<Grid.RowDefinitions>
    						<RowDefinition Height="70"/>
    						<RowDefinition Height="*"/>
    					</Grid.RowDefinitions>
    				</Grid>
    			</Viewport2DVisual3D>
    			<ModelVisual3D>
    				<ModelVisual3D.Content>
    					<DirectionalLight Color="White" Direction="0,0,-1"/>
    				</ModelVisual3D.Content>
    			</ModelVisual3D>
    		</Viewport3D>
    	</Grid>
    </UserControl>

    I added mouse events on the actual ViewPort3d Control and the Image control just to make sure both would do their thing and they seem to...

    The code-behind for that control...

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;
    using System.Windows.Media.Animation;
    namespace ViewPort3dTesting
    {
    	public partial class viewport3DControl : UserControl
    	{
    		public viewport3DControl()
    		{
    			this.InitializeComponent();
    		}
    		
    		public void AddItems()
    		{
    			myGrid.Children.Clear();
    			
    			Image img = new Image();
    			img.Source = new BitmapImage(new Uri("img1.png", UriKind.RelativeOrAbsolute));
    			img.HorizontalAlignment = HorizontalAlignment.Stretch;
    			img.VerticalAlignment = VerticalAlignment.Stretch;
    			img.Style = this.TryFindResource("ImageStyle") as Style;
    			img.ToolTip = img.Source.ToString();
    			img.MouseEnter += changeStyle;
    			myGrid.Children.Add(img);
    			Grid.SetRow(img, 0);
    			
    			Button btn = new Button();
    			btn.Content = "Click Me";
    			btn.HorizontalAlignment = HorizontalAlignment.Stretch;
    			btn.VerticalAlignment = VerticalAlignment.Stretch;
    			btn.Margin = new Thickness(5);
    			btn.Click += btnClicked;
    			myGrid.Children.Add(btn);
    			Grid.SetRow(btn, 1);
    		}
    		
    		private void btnClicked(object sender, System.Windows.RoutedEventArgs e)
    		{
    			MessageBox.Show("Clicked");
    		}
    		
    		private void changeStyle(object sender, MouseEventArgs e)
    		{
    			Image img = sender as Image;
    			img.Style = this.TryFindResource("ImageStyle2") as Style; 
    		}
    		private void viewport3D_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
    		{
    			Storyboard sb = this.TryFindResource("Storyboard1") as Storyboard;
    			sb.Begin();
    		}
    		private void viewport3D_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
    		{
    			Storyboard sb = this.TryFindResource("Storyboard2") as Storyboard;
    			sb.Begin();
    		}
    	}
    }

    And the MainWindow housing the control and which contains the button to add items dynamically to the control...

    <Window
    	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:local="clr-namespace:ViewPort3dTesting"
    	x:Class="ViewPort3dTesting.MainWindow"
    	x:Name="Window"
    	Title="MainWindow"
    	Width="640" Height="480">
    	<Grid x:Name="LayoutRoot">
    		<local:viewport3DControl x:Name="myControl" Margin="162,70.5"/>
    		<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    	</Grid>
    </Window>

    And the code-behind...

    using System.Windows;
    namespace ViewPort3dTesting
    {
    	public partial class MainWindow : Window
    	{
    		public MainWindow()
    		{
    			this.InitializeComponent();
    		}
    		private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
    		{
    			myControl.AddItems();
    		}
    	}
    }

    I stuck the sample project on my SkyDrive … http://sdrv.ms/RlBf9x   If you'd like to play with it.

    I really do hope you get it worked out quickly.

    ~Christine


    My Gallery


    Wednesday, September 05, 2012 4:58 PM
  • Hi Christine,

    Thanks for the detailed answer.

    I would like to add that i am trying to create a generic "coverflow" control and i am adding the child controls(with events) to ModelVisual3D's children and the modelvisual3D is a child of Viewport3D.

    I am using the example from the below link to create my coverflow control

    http://d3dal3.blogspot.com/2008/10/wpf-cover-flow-tutorial-part-1.html

    Any example fore the this scenario would be really helpful!


    Gopra V

    Thursday, September 06, 2012 12:58 PM