65.9K
CodeProject 正在变化。 阅读更多。
Home

Channel9 3D 浏览器(带手势)(混合智能客户端)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (19投票s)

2009年3月10日

Ms-PL

4分钟阅读

viewsIcon

35135

downloadIcon

731

关于查看 Channel9 RSS帖子的文章。

image.png

引言

我爱 Channel9,我认为这个网站应该在每个开发者的收藏夹列表中!几天前,我看到了“混合智能客户端”比赛,我想这是一个创造一个漂亮的 WPF 应用程序的好机会,该应用程序可以以 3D 的方式连接到 Channel 9,以便查看所有那些很棒的视频。

背景

不久前,我创建了一个 **WPF 3D 视图控件**,该项目托管在 Codeplex 上,它启发了我以 3D 的方式读取 Channel 9 的 RSS。所以,WPF 3D 视图控件是这个应用程序的第一块砖。正如所有 WPF 开发者都知道(或应该知道)的那样,有一个非常好的工具包可以将 2D 元素放在普通的 WPF 应用程序的 3D 内容上——这些内容是“可点击的”。该工具包的名称是 **3D Tools for Windows Presentation Foundation**,它也托管在 Codeplex 上。

Using the Code

首先,我想向您展示如何使用 3DView 控件。有两种方法可以使用此控件:XAML 和 C#。

第一种方法:XAML

创建一个标准的 WPF 应用程序,下载 3DView 控件及其依赖项,将它们添加到您的项目中(右键单击 References -> Add Reference -> Browse -> (查看下载位置) -> OK)。在 Window1.xaml 中,使用 xmlns 在您的应用程序和 WPF 3D View 程序集之间建立连接。

然后,在 Grid 元素中,创建一个 `_3DViewControl` 元素,设置其属性并添加子元素。单个子元素 `_3DViewElemet` 有一个前面元素 `_3dwns:_3DViewElement.FrontElement` 和一个后面元素 `_3dwns:_3DViewElement.BackElement`。在这些元素中,您可以放置实际的 2D 内容。

代码如下。

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Loaded="Window_Loaded"
xmlns:_3dwns="clr-namespace:_3DView;assembly=3DView"
Title="Window1" Height="466" Width="639">
	<Grid Name="myGrid" > 

	<_3dwns:_3DViewControl x:Name="My3DView" 
                                    Height="{Binding ElementName=myGrid, Path=Height}"
				Width="{Binding ElementName=myGrid, Path=Width}" 
                                    TimeSpanMiliseconds="450">
		<_3dwns:_3DViewControl.Children>
			<_3dwns:_3DViewElement>
				<_3dwns:_3DViewElement.FrontElement>
					<Button>Click me1</Button>
				</_3dwns:_3DViewElement.FrontElement>
				<_3dwns:_3DViewElement.BackElement>
					<Button>Click me11</Button>
				</_3dwns:_3DViewElement.BackElement>
			</_3dwns:_3DViewElement>

			<_3dwns:_3DViewElement>
				<_3dwns:_3DViewElement.FrontElement>
					<Button>Click me2</Button>
				</_3dwns:_3DViewElement.FrontElement>
				<_3dwns:_3DViewElement.BackElement>
					<Button>Click me22</Button>
				</_3dwns:_3DViewElement.BackElement>
			</_3dwns:_3DViewElement>

			<_3dwns:_3DViewElement>
				<_3dwns:_3DViewElement.FrontElement>
					<Button>Click me3</Button>
				</_3dwns:_3DViewElement.FrontElement>
				<_3dwns:_3DViewElement.BackElement>
					<Button>Click me33</Button>
				</_3dwns:_3DViewElement.BackElement>
			</_3dwns:_3DViewElement>
		</_3dwns:_3DViewControl.Children>
	</Grid>

</Window>

第二种方法:C#

要动态添加元素,您必须删除所有 `<_3dwns:_3DViewElement>` 元素。然后,您应该使用下一节中描述的 `AddNewChild` 方法。

3DView 控件方法

一个 `_3DViewControl` 继承自 `UserControl`。因此,除了所有 `UserControl` 方法之外,我还添加了一些新方法用于添加和删除新子元素。

/// <summary>
/// Adds a new child
/// </summary>
/// <param name="child">Child to add</param>
public void AddNewChild(_3DView._3DViewElement child)
{

...
}

/// <summary>
/// Removes the element located at an index
/// </summary>
/// <param name="index">Element index to remove</param>

public void RemoveAt(int index)
{
...
}

例如,我将向您展示 Channel 9 RSS Explorer 元素的添加方式。对于前面的元素,我创建了一个 XAML UserControl 并将其命名为 `FrontDisplayControl`。该元素的标记是

<Grid Background="White" Height="250">
    <Grid.RowDefinitions>
		<RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="10"/>
    </Grid.RowDefinitions>
    <TextBlock Margin="2" x:Name="TitleTextBlock"
           Style="{StaticResource CustomHeaderTextBlockStyle}" 
           HorizontalAlignment="Left" TextWrapping="Wrap" Grid.Row="0"/>
        
	<Grid Grid.Row="1" VerticalAlignment="Top">
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="80"/>
			<ColumnDefinition/>
		</Grid.ColumnDefinitions>
		
		<Image Margin="2" x:Name="MyImage"
                      Visibility="Visible" VerticalAlignment="Top"
                      HorizontalAlignment="Left" Grid.Column="0"/>
		<TextBlock Margin="3,0,3,0" Background="White"
                      x:Name="DescriptionTextBlock"
                      Style="{StaticResource NormalTextBlockStyle}" 
		Grid.Column="1" TextWrapping="Wrap"/>
	</Grid>

</Grid>

正如您所看到的,这里是图片和帖子的描述。

对于后面的元素,标记是

<StackPanel Background="Transparent">
	<Grid HorizontalAlignment="Center" VerticalAlignment="Bottom">
		<Image x:Name="PlayImage" Source="..\Images\play.png" Width="25"
                      Height="25" HorizontalAlignment="Left"/>
		<Image x:Name="PauseImage" Source="..\Images\pause.png" Opacity="0"
                      Width="25" Height="25" HorizontalAlignment="Left"/>
	</Grid>
	<Grid>
		<MediaElement x:Name="MyPlayer" LoadedBehavior="Manual"
                      UnloadedBehavior="Stop"/>
	</Grid>
</StackPanel>

后面的元素有一个 `MediaElement`,您可以在其中播放视频。要观看视频,我所要做的就是翻转元素。

从网站读取 RSS 后,您会创建一个 `_3DViewElement`、一个 `FrontDisplayControl` 和一个 `BackDisplayControl`。对于前面的控件,设置来自 <img> 标签的图片、标题和描述,对于后面的元素,设置视频 URL。然后,调用 `AddNewChild` 方法。就是这样!

//create a new element...
_3DViewElement element = new _3DViewElement();
//front element
FrontDisplayControl frontControl = new FrontDisplayControl(img);
frontControl.Title = __MyNodeItem["title"].InnerText;
frontControl.AddressLink = __MyNodeItem["link"].InnerText;
frontControl.Description = text;
//back element
BackDisplayControl backControl = new BackDisplayControl();
...
backControl.VideoLink = url;
element.FrontElement = frontControl;
element.BackElement = backControl;
this.My3DView.AddNewChild(element);

3DView 控件属性

像所有控件一样,它有一些特定的属性。

/// <summary>
/// Gets or sets the current item
/// </summary>
public int CurrentItem
{ get; set; }

/// <summary>
/// Gets or sets the current item offset on Z axis
/// </summary>
public double CurrentItemOffset { get; set; }

/// <summary>
/// Gets or sets the miliseconds in the animation duration
/// </summary>
public int Duration { get; set; }

/// <summary>
/// Sets the Visibility of Flip button
/// </summary>
public bool ViewFlipButton
{
	set
	{
		if (value == false)
			this.FlipButton.Visibility = Visibility.Collapsed;
		else
			this.FlipButton.Visibility = Visibility.Visible;
	}

	get
	{
		return this.FlipButton.Visibility == Visibility.Visible;
	}
}

/// <summary>
/// flip button content
/// </summary>
public string FlipButtonContent
{
	set
	{
		if (value == null)
			return;

		this.FlipButton.Content = value;
	}
}

/// <summary>
/// Gets or sets the Z coordonate of the camera position
/// </summary>
public double CameraZPosition
{
	set
	{
		Point3D point = this.MyCamera.Position;

		this.MyCamera.Position = new Point3D(point.X, point.Y, value);
	}
	get
	{
		return this.MyCamera.Position.Z;
	}
}

属性表

属性名 描述
CurrentItem 获取或设置当前项。如果您想从不同的项(例如中间项)开始,则使用它。
CurrentItemOffset 获取或设置当前项的 Z 坐标。
持续时间 将当前项放入堆栈并显示下一项所需的时间(以毫秒为单位)。
ViewFlipButton 获取或设置“翻转”按钮的可见性。
FlipButtonContent 获取或设置“翻转”按钮的内容。
CameraZPosition 摄像机的 Z 值。

添加手势

最近,我玩了一台 IBM Think Pad X41,它也是一台平板电脑,有一个 TrackPoint 作为输入设备。当然,您可以连接一个鼠标设备,但只要有触控笔,您就不需要鼠标。所以,我想让这个应用程序响应手势。我所做的就是覆盖一些鼠标移动方法,例如 3D 视图控件中的 `OnMouseMove`、`OnMouseUp` 和 `OnMouseDown`。

但首先,您必须删除 `TrackballDecorator` 类(这是一个 3D 工具类)中的操作(`Zoom` 和 `Track`)。

/// <summary>
/// Previous position point
/// </summary>
Point __PreviousPosition;

/// <summary>
/// Overrides the OnMouseMove
/// </summary>
/// <param name="e">EventArgs</param>
protected override void OnMouseMove(MouseEventArgs e)
{
	base.OnMouseMove(e);

	if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
	{
		Point position = e.GetPosition(this);

		if (position == __PreviousPosition) return;

		if (position.Y < __PreviousPosition.Y - 50)
		{
			this.CameraZPosition -= 0.1d;
			__PreviousPosition = position;
		}

		if (position.Y > __PreviousPosition.Y + 50)
		{
			this.CameraZPosition += 0.1d;
			__PreviousPosition = position;
		}

		if (position.X > __PreviousPosition.X + 75)
		{
			this.MoveItem(RotateDirection.Left);

			__PreviousPosition = position;
		}

		if (position.X < __PreviousPosition.X - 75)
		{
			this.MoveItem(RotateDirection.Right);

			__PreviousPosition = position;
		}
	}
	else
		__PreviousPosition = e.GetPosition(this);
}

/// <summary>
/// Overrides the OnMouseDown
/// </summary>
/// <param name="e">EventArgs</param>
protected override void OnMouseDown(MouseButtonEventArgs e)
{
	base.OnMouseDown(e);

	__PreviousPosition = e.GetPosition(this);
}

/// <summary>
/// Overrides the OnMouseUp
/// </summary>
/// <param name="e">EventArgs</param>
protected override void OnMouseUp(MouseButtonEventArgs e)
{
	base.OnMouseUp(e);

	__PreviousPosition = e.GetPosition(this);
}

手势是

  • 如果您想查看下一项(右侧项),只需将当前项从右向左拖动。
  • 如果您想查看上一项(左侧项),只需将当前项从左向右拖动。
  • 如果您想放大,只需从下向上拖动。
  • 如果您想缩小,只需从上向下拖动。

如果您问我为什么选择这些方向,我只有一个答案:在我看来,这些操作是自然的。

您可以在图片中看到该应用程序在 IBM ThindPad 上运行。

gesture.jpg

我创建了一个 视频,展示了这些手势。

控件样式

这里我将不讨论应用程序用户界面的样式设置。如果您想了解更多信息,可以从 这里开始。

我希望您会使用这个应用程序,或者至少是 WPF 3D 视图控件。:)

希望我能赢得这次比赛,买一台带有触摸屏界面的电脑,让这个应用程序支持多点触控!:)

© . All rights reserved.