JukeBox API - 面向艺术家和开发者的项目
旨在促进程序员和图形艺术家之间联合开发的项目。

引言
我首先要讨论一下这个项目是什么,又不是什么。它不是一个即插即用的点唱机。它就是它所说的“点唱机 API”。它的前端功能齐全,并且确实可以播放媒体。我现在正在听披头士乐队的 FLAC 音频。但是它没有后端可言,你必须手动编写项目中的 `XmlData` 文件夹里的 XML 文件。如果你不想这样做,并且你也没有意愿去开发一个自动化的后端,那么这里对你来说就没有什么可看的了。
我开发这个项目是因为我想尝试一个 WPF 解决方案,它同样面向图形艺术家和代码开发者。当我几个月前开始使用 WPF 时,我读到它是一个供编码者和艺术家共同开发项目的良好环境。在这几个月里,尽管在互联网上进行了大量的研究,但我没有发现一个项目曾尝试过艺术家/编码者协作。所以我选择开发这个项目。
出于上述原因,我不会花太多时间讨论这个项目所涉及的技术细节。我费了很大力气来详细记录代码,并且在我做了非标准编码技术的事情时,提供了详细的代码解释。我打算做的是仔细介绍一个人需要遵循的各个步骤,以便将当前的点唱机演示重新构想成他们自己的视觉创作。
在使用软件之前,你需要创建一个 `C:\XMLData` 目录,并用一个 `JukeQueue.xml` 数据集(包含在内)和几个 `FlowDocuments` 来填充它。我稍后会更详细地讨论这个要求——以及如何修改代码来更改目录位置。我只是想提前提一下——我讨厌“坑”被埋在细则里。
术语
因为这是一个主要由图形驱动的项目,我想花一点时间来谈谈我将用于描述界面的术语。
整体图形界面由 4 个外部停靠面板组成,中间是一个书本。为了将图形缩小到本文的尺寸,上面快照中的一部分界面已被裁剪掉。左侧和右侧面板带有彩色条。顶部的面板左侧是当前歌曲的点唱机标签,右侧是一个带有点唱机队列播放列表的列表框。底部面板有 7 个选择按钮(标有 A-G),3 个圆形媒体操作按钮,两个滑块(音量和平衡),一对左/右翻页按钮,以及一个带有两个声音片段选项的组框。我稍后会详细介绍这些控件,此时你只需要理解我将要使用的术语。如果我们都在同一个房间里,我可以使用激光笔烧穿 6 英寸的砖头,那会很好,但我们不在,而且他们已经把激光笔从我这里拿走了。
有 6 个彩色条,左侧 3 个,右侧 3 个,与左侧的彩色条相呼应。每个彩色条由 3 个条带组成。在讨论项目的这部分时,我不会使用“列”这个词;“列”这个词太笼统了。每个彩色条的中间条带有一个白色的“灵魂”(借用 Atari 的说法),从上到下在中间条带中漂浮。外侧条带具有双色渐变,以 3-5 秒的周期动画变化颜色,以产生发光的效果。
项目中心的“书本”是 Mitsuru Turuta 的翻页项目的一个修改版本。如果你想了解更多,在他的博客上有一个指向他博客的超链接,该博客位于书本末尾的“关于”页面。 **Microsoft Public License** 也在这个页面上。请不要删除它。Mitsuru 在微软工作,微软拥有该许可证。其中一项条款是,其公共许可证必须随 Mitsuru 的代码一起包含。我只是在“关于”页面上放了一个 `FlowDocument`,并在项目中包含了许可证。书本的每一页都是一个带有代码隐藏的 XAML `UserControl`。我稍后会更详细地讨论设置。你现在只需要明白的是,书本的页面本质上是选项卡控件面板,只是没有选项卡。封面之后的第一个页面是 Mitsuru 项目自带的一个示例表单。我将其保留仅用于演示目的。有关更多信息,请参阅 Turuta 先生的博客。
对于那些技术更倾向的人来说——这个项目本质上是由 XAML `UserControl` 和绑定到 `listbox` 的 XML `dataset` 组成的。
没门!
如果你有一点艺术天赋,你可能会看着 JukeBox API 说:“不错的尝试。” 我对此表示满意。首先,我不是一个平面设计师;其次,这个项目是为了展示可能性而构建的,而不是为了展示可接受性。例如,底部控制面板上的前 3 个选择按钮使用了梅子红色,而最后 4 个使用了更亮的红色。让你高兴的是,`\images` 文件夹里有一整套每种颜色的。我只是想展示每种颜色。书本中包含歌曲标签的每一对相对页面都使用不同的标签,并且布局也经常不同。这些都只是可能性的例子,绝不是你可能想看到的东西。
所以,让我们开始分解图形,并探索如何控制演示。我将从彩色条及其条带开始。如我所提到的,外侧条带由标准的 XAML 渐变标记组成。所有这些渐变的颜色都在 `Windows1.xaml` (图 1) 顶部的 **Gradient Stop Collection** 中。在这里你可以更改外侧条带的颜色。只有 3 种颜色组合会影响左侧和右侧。例如,如果你更改黄色/金色组合,你就会更改左侧和右侧的黄色/金色彩色条。除非你想改变演示的所有内容,否则请不要动黑色/银色组合。
<!-- G R A D I E N T S T O P C O L L E C T I O N S -->
<!-- If you want to change the colors of the outer strips for the Juke Bars -->
<!-- change these values and both the left and right dock bars will be upd...-->
<GradientStopCollection x:Key="OuterColmnA" >
<GradientStop Color="Orange" Offset="0.0" />
<GradientStop Color="Gold" Offset="1.00" />
</GradientStopCollection>
在 Gradient Stop 的正下方是 **Color Bar Animation Storyboards** (图 2)。这些标记控制着上方定义的条带中使用的旋转颜色的时间和颜色。我可以详细介绍如何修改它们,但如果你开始摆弄标记,你会学得更快。将值 `TO=”Yellow”` 改为 `TO=”GREEN”` 并运行项目。你将立即看到效果!持续时间的值不言自明——以秒为单位。
<!-- Color Bar Animation Storyboards -->
<!-- If you want to change the oscillating gradients in the outer strips
<!-- this is the place! -->
<!-- Both the Left and Right Dock Panels use these values.
<Storyboard>
<!-- Yellow Bar Animation -->
<ColorAnimation Storyboard.TargetName="PlayAround"
Storyboard.TargetProperty="Fill.GradientStops[1].Color"
To="Yellow" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever"></ColorAnimation>
<ColorAnimation Storyboard.TargetName="PlayAroundRght"
Storyboard.TargetProperty="Fill.GradientStops[0].Color"
To="Yellow" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever"></ColorAnimation>
向下移动到左侧面板的标记值,并查找中间的灵魂条带 (图 3)。你需要更改背景颜色以匹配你在渐变条带中选择使用的颜色。完成左侧面板后,别忘了去右侧面板更改那里的中间灵魂条带。与 **Gradient Stop Collections** 不同——你必须单独更改左侧和右侧面板。正如你所看到的,这些中间灵魂条带的工作方式与外侧条带不同。漂浮灵魂的代码要求它们被处理为 `UserControl`,这需要一些代码隐藏:请参阅 `CustomDrawnElement.cs`。
<!-- L E F T P A N E L center Spirit strips -->
<!-- L E F T P A N E L center Spirit strips -->
<!-- These values are for the LEFT PANEL ONLY!!! -->
在我们继续浏览 `Windows1.xaml` 列表之前——让我们回到列表的顶部。那里有两个 `ImageBrush` 标记,它们影响顶部面板的演示 (图 4)。其中一个带有 `x:key=”JukeBrush”`——它下面的标记带有 `x:key=”JukeBrushQueue”`。这两个 `ImageBrush` 标记决定了在顶部面板中使用哪个标签。即使两个标记使用相同的 `ImageSource` 值,也不要删除其中一个 `ImageBrush` 标记——它们由于屏幕上标签大小不同而具有不同的 `Viewport` 值。
<!-- Default Juke Song Label -->
<ImageBrush x:Key="JukeBrush" TileMode="None"
ViewportUnits="Absolute" Viewport="0 0 300 90"
ImageSource="images\jb45lb08.jpg" Opacity="0.90">
</ImageBrush>
<ImageBrush x:Key="JukeBrushQueue" TileMode="None"
ViewportUnits="Absolute" Viewport="0 0 222 62"
ImageSource="images\jb45lb08.jpg" Opacity="0.80">
</ImageBrush>
让我们转向顶部面板,它奇怪地位于 `Window1.xaml` 列表的底部附近。由于 `jukelabel` 背景图像已经处理好了,`FontFamily` 和 `Foreground` 颜色是剩下的唯一有实际意义的属性。我正在使用 `FontFamily=”OCR-A II”`,但我无法想象大多数人会想坚持使用它。根据你的需要更改这些值。
(注意:不要改变面板标记的顺序——它会影响哪些面板控制演示的角落。如果你将顶部和底部面板列在左侧和右侧面板之前——彩色条将不会从屏幕顶部延伸到底部。)
接下来,让我们看看底部面板的标记,它位于左侧和右侧面板的标记之后,顶部面板之前。底部面板的所有图形按钮都是 `ToggleButtons`,它们需要两个图形值,一个用于打开状态,一个用于关闭状态。'A' 选择按钮的值如下 (图 5)。如果你仔细观察,你会发现在 `Setter` 标记中嵌入了一个“关闭”按钮(默认)和一个“开启”按钮。所有切换按钮都这样工作,包括媒体操作按钮。暂时不要动滑块控件——最小/最大值必须设置为其当前范围才能与媒体播放器正确工作。
<!-- Page Set _A_ -->
<ToggleButton Width="78" Height="42" Background="Transparent" Margin="0" Name="PageA" >
<ToggleButton.Template>
<ControlTemplate>
<Image Width="64" Height="40" Name="PanelA"
Source="images\RectPlumABtn.png" VerticalAlignment="Center"/>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<!-- The Setter control changes the
button graphic to it's 'ON' image. -->
<Setter TargetName="PanelA" Property="Source"
Value="images\RectMetalABtnOn.png" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
现在移到 `Windows1.xaml` 数据集的底部,查找 `controls:Book.ItemTemplate` (图 6)。在模板中,你会看到 `UCPages` 文件夹中包含的 `UCPages`。`UCPages` 的顺序构成了书本的演示。书本将逐页匹配这里的 `UCPages` 列表。你会看到第一组 `UCLabels` 的左页直到第 3 页才出现。选择按钮 A 显示第 3-4 页。第 3-4 页显示的内容在 `controls:Book.ItemTemplate` 中确定。程序中没有任何内容将 `UCLabels` 直接绑定到选择按钮。你需要自己进行匹配。
</controls:Book.ItemTemplate>
<!-- These are the pages and their order in the Juke Song Book. -->
<local:UCCube /> <!-- Book Cover -->
<local:UCControls /> <!-- Page 1 -->
<local:UCFlowDoc Title="Hello!" Body="C:\XMLData\... />
<local:UCLabelAl /> <!-- Page 3 -->
<local:UCLabelAr /> <!-- Page 4 -->
<local:UCLabelBl /> <!-- etc. -->
<local:UCLabelBr />
让我们在 `Solution Explorer` 中转到 `UCPages folder` 并打开它。有一系列 `UCLabel` 页,从 `UCLabelAl` 到 `UCLabelGr`。小写的 l 和 r 代表左/右。书本中的每一页由两个列表框组成,每个列表框包含 10 个标签。这些标签中的值在 `XMLData` 文件夹的 XML 文件中。每对相对页都有一个 XML 文件。点唱机标签的背景图片在 images 文件夹中,它们都遵循 `JukeLabel___.png` 的命名约定。(图 7)。查看 `UCLabel__.xaml` 中的注释 `<!-- Listbox JukeLabel Background Image –->` 和 `ImageBrush` 的标记。`ImageBrush` 元素旁边是 `ImageSource=""` 属性,它指向用于 `JukeLabel` 背景的图形。
<XmlDataProvider x:Key="SongsLeft" Source="\XMLData\PlaylstAI.xml"
XPath="Playlist/Column[@Nbr='1']" />
<XmlDataProvider x:Key="SongsRght" Source="\XMLData\PlaylstAI.xml"
XPath="Playlist/Column[@Nbr='2']" />
<!-- Listbox JukeLabel Background Image -->
<ImageBrush x:Key="JukeBrush" TileMode="None"
Viewport="0 0 222 62" ViewportUnits="Absolute"
ImageSource="\images\JukeLabelClassic.png" Opacity="0.95">
</ImageBrush>
我使用开源软件包 `The Gimp` 创建了大多数 `JukeLabels`。如果你想尝试一下,只需创建一个 320x110 dpi 的图像即可。项目材料中附有一个附录,其中详细介绍了如何使用 `The Gimp` 创建自己的图形。如果你不熟悉 `The Gimp`——它很好,它是免费的,并且互联网上有很多不错的教程。
不要假设不同的 `UCLabel UserControl` 是通用的。大多数都经过调整,以配合它们配对的 `JukeLabel` 图形。每个 `JukeLabel` 页面都有其自己独特的 UserControl `UCLabel__ xaml` 标记。我这样做是为了在自定义 `jukelabels` 时获得最大的灵活性。有一种方法可以创建一个单一的 `UCLabel` 控件。你需要理解 `UserControl` 并查看 `UCFlowDoc` 示例。我在该 `FlowDoc UserControl` 的初始化期间传递参数。如果你愿意,你也可以对 `UCLabel` 及其 `XMLDataProvider` 参数执行相同操作。
图形部分至此结束。有 4 个地方你需要进入代码进行修改。幸运的是,这些修改都不复杂。
- 如果你要自己制作,不如玩得开心一点。我添加了一个“声音片段”功能,它会在每首歌之前随机播放一个不同的短声音片段。该方法名为 `SoundBiteSetUp()`,位于 `Windows1.xaml.cs` (图 8)。第一个声音片段名为“jukebox.wav”。我将它从几个不同的来源拼凑而成——它由一些唱片噪音夹在一些点唱机机械声音之间组成。其余 14 个 jukeEffects 都是标准的 Microsoft `Chimes.wav` 音效。用你自己的声音片段替换它们。只需确保在将媒体文件复制到 `\Resources` 后,转到媒体的 WPF 属性并将“**Copy to Output Directory**”更改为“**Copy always**”。否则代码将无法播放媒体。你也应该将属性框中的 **Build Action** 设置为“**Content**”。
RandomNbr = (RandomNbrx % 14); switch (RandomNbr) { case 0: jukeEffect = new Uri(@"Resources\jukebox.wav", UriKind.Relative); break; case 1: jukeEffect = new Uri(@"Resources\chimes.wav", UriKind.Relative); break; case 2: jukeEffect = new Uri(@"Resources\chimes.wav", UriKind.Relative); break;
图8。 -
媒体 `Open` 语句的 `Uri` 路径在程序中是硬编码的。我知道这是不好的,但我厌倦了每次将媒体移动到另一个驱动器标签时都要更改 XML。代码位于 `Window1.xaml.cs` 的 `NextJukeSongFromQueue` 方法中。
string uriFilePath = @"M:" + JukeLabelElement["FilePath"].InnerText;
将其更改为你自己的驱动器盘符。其余路径在 XML `PlayLst dataset` 中。
- 值:`@"C:\XMLData\"` 在程序中有几个地方被硬编码。你需要一个目录来存放几个支持文件。如果你不想创建 `C:\XMLData` 目录,那么你需要将 `C:\XMLData` 的每次出现替换为你选择使用的任何内容。
- 当我第一次找到页面软件项目时,我想修改翻页动作,使其更像点唱机中的面板。我最终决定将 JukeLabels Book 视为一本杂志更有趣。我创建了一个简单的 `FlowDocument` 页面,它可以接受一个标题和一个 `Uri` 来表示 `UserControl` (图 9)。你可以创建任意数量的这些页面。选择按钮 A-G 可以处理第 3-16 页。一旦用完这些槽,你将需要手动翻页或更改代码以添加更多选择按钮。
<local:UCFlowDoc Title="Hello!" Body="C:\XMLData\Introduction.xaml"/>
图9。
我确信我遗漏了一些东西,但我希望你会同意,你可以用这个骨架点唱机并修改它,使其看起来、行为和听起来都如你所愿。通过 `UCFlowDoc` 页面,你甚至可以将自己的博客混合进去。
如果你还在看?
那么我从这一切中学到了什么?我断断续续地工作了这个代码几个月,即使是我自己也有点对所有选项感到困惑。我认为微软需要为开发者提供一个向导或脚本语言,让我们能够像对待 SQL 存储过程一样对待 XAML 标记。有了存储过程,我可以保护我的 SQL,但可以为业务用户提供对他们需要查询的数据的变量的访问。我希望能够创建一个脚本,使某些 XAML 元素和属性能够被图形界面专家访问,而无需让他们深入研究大量 XAML 代码,并冒着他们进行可能导致问题的修改的风险。这需要额外的努力来完成额外的标记并编写任何必要的提示、说明或注释。每个项目团队都需要权衡利弊。
目前我认为编码人员和图形界面专家在大型项目上协作的想法就像来自高层的备忘录——它是一个幻想。我也认为 WPF 代码总体来说编写成本更高。利用 WPF 的高级图形和媒体功能似乎是额外努力的主要理由之一。如果程序员和平面设计师之间的协作很笨拙,那么我看不出我们将如何获得用户期望的生产力。WPF 可能最终会成为一项非常、非常不错的利基技术。
我还对免费图形/媒体材料的稀缺性感到困惑。我可能不知道最好的查找地点,但我确实花了一些时间查找。我可以获得免费的代码,免费的代码片段,免费的程序,免费的故障排除建议:即使是获取一个漂亮的图标,也几乎不可能不担心一些隐藏的版权。我可能是错的,但我没有在图形领域看到像编程世界那样普遍存在的开源精神。在房子后台的图形方面有 CodeProject 的等价物吗?如果没有——那么很难进行联合项目实验,并一起走过学习曲线。
当然,我也许是错的。这是一个你可以用来运行你自己的小实验并查看结果的项目。我毫不怀疑你会成功。问题是,你会怎么做?需要开发哪些编码工具和图形资源才能使流程更具生产力?
Using the Code
JukeBook 的第 2 页有介绍和设置说明。我在代码中添加了很多注释。我添加了一个 `filewatcher` 来强制双向绑定。该代码可以在 `MyXMLDataProvider` 中找到。它只是继承 `XMLDataProvider` 并附加 `filewatcher` 方法。在 `graphics` 文件夹中还有一个图形操作指南。
负责书本翻页的 MitsuControls 没有提供文档或注释。我为控件逻辑添加了注释,但控制翻页效果的图形和几何/三角函数保持不变。换句话说,你得自己摸索。我修改了代码以允许自动翻页。你不能仅仅在代码中假装点击翻页按钮来进行翻页。这是行不通的。Mitsu 代码会翻页,然后设置下一组页面。如果你在它设置下一页时请求新页面,它会忽略你的请求。我在 `Book.cs` 中添加了 `TargetPageNbr` 属性来方便自动翻页。
待办事项列表
接下来我必须要做的是购买一个 19 英寸的触摸屏,并编程界面以适应屏幕。不幸的是,19 英寸的屏幕大约要 900 美元。我会在门口接受捐款。
我确实需要编写一个实用程序来帮助自动化 PlayList XML 文件。我一直在使用 J.River 的一个免费软件包 Media Jukebox。它没有点唱机,但它能够导入标签(包括 FLAC!!!)并导出 XML。它导出的信息比我想要的要多得多,但我可以绕过它。一个好的拖放例程应该能在 GUI 端让事情相当直接。
能够保存 `JukeQueue` XML 文件会很好。这样就可以实现“播放列表”功能。
JukeQueue 中没有穿梭或随机播放功能。软件按照选择的顺序播放歌曲。这并不难实现。我只是不确定它的使用频率。
我想在程序中创建一个资源,它只是一个 XML 数据集,其中包含一列 4 位随机数。这些数字将被用作令牌,允许个人在输入有效令牌后点播 6 首歌曲。这个功能唯一的用途是在聚会上,有几个想成为 DJ 的人想让其他人都听他们的(也是唯一的)喜欢的音乐。有了令牌,他们就能像其他人一样点播 6 首歌曲。我承认这是一个解决我个人癖好的功能,但我们自己制作软件不就是为了这个吗?
致谢
请参阅 JukeBook 的“关于”页面,了解 Microsoft Public License 和 Mitsu 先生的博客链接。他目前没有对翻页控件进行增强,但他会回答问题。
`MyXMLDataProvider` 中文件监视功能的代码片段来自 此链接。
历史
- 2009 年 8 月 21 日:初始版本