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






4.88/5 (19投票s)
关于查看 Channel9 RSS帖子的文章。

引言
我爱 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 上运行。
我创建了一个 视频,展示了这些手势。
控件样式
这里我将不讨论应用程序用户界面的样式设置。如果您想了解更多信息,可以从 这里开始。
我希望您会使用这个应用程序,或者至少是 WPF 3D 视图控件。:)
希望我能赢得这次比赛,买一台带有触摸屏界面的电脑,让这个应用程序支持多点触控!:)